package utility;

import java.awt.Color;
import java.util.Random;

public class Perlin {
	/*static float persistence=0.125f;
    static int numberOfOctaves=3;
    static float hScale=0.5f;
    static float vScale=0.5f;*/
/*
    public static float getHeight(float x, float z)
    {
        float height=0;
        float frequency;
        float amplitude;

        x*=hScale;
        z*=hScale;

          float p=persistence;
          int n=numberOfOctaves-1;

          for (int i=0;i<n;i++)
          {
            frequency=(float)Math.pow(2,i);
            amplitude=(float)Math.pow(p,i);
            height=height+interpolatedNoise(x*frequency,z*frequency)*amplitude;
          }
        return height*vScale;
    }
    public static float noise(int x, int y)
    {
        int n=x+y*57;
        n=(n<<13)^n;
        return (1.0f-((n*(n*n*15731+789221)+1376312589)&0x7fffffff)/1073741824f);
    }
    private static float interpolatedNoise(float x, float y)
    {
        int integer_X=(int)x;
        float fractional_X = x-integer_X;

        int integer_Y=(int)y;
        float fractional_Y=y-integer_Y;

        float v1 = noise(integer_X,integer_Y);
        float v2 = noise(integer_X+1,integer_Y);
        float v3 = noise(integer_X,integer_Y+1);
        float v4 = noise(integer_X+1,integer_Y+1);

        float i1=interpolate(v1,v2,fractional_X);
        float i2=interpolate(v3,v4,fractional_X);

        return interpolate(i1,i2,fractional_Y);
    }
    private static float interpolate(float a, float b, float x)
    {
        // linear
//        return  a*(1-x) + b*x;

        // cosine
        float ft=x*3.1415927f;
        float f=(float)((1-Math.cos(ft))*0.5f);
        return  a*(1-f)+b*f;

    }
    
    
*/    
    
    
    
    
    ////////  BERTRAND //////////////////
    
    public static float[][] GenerateWhiteNoise(int width, int height)
    {
        Random random = new Random(); //Seed to 0 for testing
        float[][] noise = new float[width][height];
     
        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                noise[i][j] = (float)random.nextDouble() % 1;
            }
        }
     
        return noise;
    }
    
    
    
    
    public static float[][] GenerateSmoothNoise(float[][] baseNoise, int octave)
    {
       int width = baseNoise.length;
       int height = baseNoise[0].length;
     
       float[][] smoothNoise = new float[width][height];
     
       int samplePeriod = 1 << octave; // calculates 2 ^ k
       float sampleFrequency = 1.0f / samplePeriod;
     
       for (int i = 0; i < width; i++)
       {
          //calculate the horizontal sampling indices
          int sample_i0 = (i / samplePeriod) * samplePeriod;
          int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
          float horizontal_blend = (i - sample_i0) * sampleFrequency;
     
          for (int j = 0; j < height; j++)
          {
             //calculate the vertical sampling indices
             int sample_j0 = (j / samplePeriod) * samplePeriod;
             int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around
             float vertical_blend = (j - sample_j0) * sampleFrequency;
     
             //blend the top two corners
             float top = Interpolate(baseNoise[sample_i0][sample_j0],
                baseNoise[sample_i1][sample_j0], horizontal_blend);
     
             //blend the bottom two corners
             float bottom = Interpolate(baseNoise[sample_i0][sample_j1],
                baseNoise[sample_i1][sample_j1], horizontal_blend);
     
             //final blend
             smoothNoise[i][j] = Interpolate(top, bottom, vertical_blend);
          }
       }
     
       return smoothNoise;
    }
    
    public static float Interpolate(float x0, float x1, float alpha)
    {
       return x0 * (1 - alpha) + alpha * x1;
    }
    
    
    
    public static float[][] GeneratePerlinNoise(float[][] baseNoise, int octaveCount)
    {
       int width = baseNoise.length;
       int height = baseNoise[0].length;
     
       float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
     
       float persistance = 0.5f;
     
       //generate smooth noise
       for (int i = 0; i < octaveCount; i++)
       {
           smoothNoise[i] = GenerateSmoothNoise(baseNoise, i);
       }
     
        float[][] perlinNoise = new float[width][height];
        float amplitude = 1.0f;
        float totalAmplitude = 0.0f;
     
        //blend noise together
        for (int octave = octaveCount - 1; octave >= 0; octave--)
        {
           amplitude *= persistance;
           totalAmplitude += amplitude;
     
           for (int i = 0; i < width; i++)
           {
              for (int j = 0; j < height; j++)
              {
                 perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
              }
           }
        }
     
       //normalisation
       float min=Float.MAX_VALUE,max=Float.MIN_VALUE;
       for (int i = 0; i < width; i++)
       {
          for (int j = 0; j < height; j++)
          {
             perlinNoise[i][j] /= totalAmplitude;
             if(perlinNoise[i][j] < min) min=perlinNoise[i][j];
             if(perlinNoise[i][j] > max) max=perlinNoise[i][j];
          }
       }
       max=max-min;
       for (int i = 0; i < width; i++)
       {
          for (int j = 0; j < height; j++)
          {
        	  perlinNoise[i][j]=perlinNoise[i][j]-(min-0.001f);
        	  perlinNoise[i][j]=perlinNoise[i][j]*1/(max+0.01f);
        	  
          }
       }
     
       return perlinNoise;
    }
    
    
 
    /////// BERTRAND  ///////////////////////
    
    
    
    
    
    
    
    
    public static void main(String[] args){
    	
    	float[][] f = GeneratePerlinNoise(GenerateWhiteNoise(1000, 1000), 8);
    	
    	for(int i = 0 ; i < 10 ;  i++){
    		for(int j = 0 ; j < 10 ; j++){
    			System.out.print(f[i][j]+"\t");
    		}
    		System.out.println();
    	}
    }
    
}
